package com.ray.basic;

import com.google.common.cache.*;
import com.google.common.util.concurrent.ListenableFuture;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * 本机缓存, 类似于有过期时间的 ConcurrentHashMap
 * 好像可以用来维持 key-> 数据库连接 这样的东西
 * @author Ray
 */
public class C41Caches {


    public static void main(String[] args) {
        // 创建一个缓存, 就有我就返回, 没有就先加载再返回
        // 这个写过期和读过期, 是并行的, 读操作并不会刷新写操作的过期时间
        LoadingCache<String, Double> resCache = CacheBuilder
                .newBuilder()
                .maximumSize(100)
                .expireAfterAccess(30, TimeUnit.MINUTES)
                .expireAfterWrite(2, TimeUnit.DAYS)
                .removalListener(new RemovalListener<String, Double>() {
                    @Override
                    public void onRemoval(RemovalNotification<String, Double> notification) {
                        // 这里面也可以塞RemovalListeners.asynchronous, 这样删除监听就是异步操作的。
                        // 删除的时候可以干点什么, 比如数据库释放连接, 释放读取的资源什么的
                    }
                })
                .build(new CacheLoader<String, Double>() {
                    @Override
                    public Double load(String key) throws Exception {
                        Double random = Math.random();
                        return random;
                    }

                    @Override
                    public ListenableFuture<Double> reload(final String key, Double prevGraph) {
                        // 这个有点复杂, 没细看
//                        if (neverNeedsRefresh(key)) {
//                            return Futures.immediateFuture(prevGraph);
//                        } else {
//                            // asynchronous!
//                            ListenableFutureTask<Graph> task = ListenableFutureTask.create(new Callable<Graph>() {
//                                public Graph call() {
//                                    return getGraphFromDatabase(key);
//                                }
//                            });
//                            executor.execute(task);
//                            return task;
//                        }
                        return null;
                    }

                });

        // 缓存可以这样手动在外面插入
        resCache.put("2", 2.2);

        try {
            // 也可以在查询的时候指定 加载不存在的缓存的方法
            resCache.get("1", new Callable<Double>() {
                @Override
                public Double call() throws Exception {
                    return Math.random();
                }
            });
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }
}
